package com.dycong.common.database.mongoDB;

import com.dycong.common.reflect.ClassUtil;
import lombok.extern.log4j.Log4j;
import org.hibernate.Criteria;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.criterion.MatchMode;
import org.hibernate.criterion.Projections;
import org.hibernate.criterion.Restrictions;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.io.Serializable;
import java.util.Collection;
import java.util.Date;
import java.util.List;
import java.util.Map;

/**
 * Created by yu on 15-8-25.
 * todo OMS里从mysql简单读取数据的工具类使用了org.hibernate.criterion类似与mybatis的一中操作
 */
@Component
@Log4j
public class BaseDao {

    public static final String STARTKEY="start_";
    public static final String ENDKEY="end_";
    @Resource
    SessionFactory sessionFactory;

    public Session getSession(){
        return  sessionFactory.getCurrentSession();
    }

    public <T> T get(Class<T> clazz, Serializable id) {
        return (T) sessionFactory.getCurrentSession().get(clazz, id);
    }

    public <T> List<T> getList(Class<T> clazz) {
        return sessionFactory.getCurrentSession()
                .createCriteria(clazz)
                .setCacheable(true)
                .list();
    }

    public <T> List<T> getListByField(Class<T> clazz, String fieldName1, Object value1,String  fieldName2, Object value2 ) {
        Criteria criteria =sessionFactory.getCurrentSession().createCriteria(clazz);
        if (fieldName1 != null && !fieldName1.isEmpty()){
            criteria.add(Restrictions.eq(fieldName1, value1));
        }
        if (fieldName2 != null && !fieldName2.isEmpty()){
            criteria.add(Restrictions.eq(fieldName2, value2));
        }
        return criteria.setCacheable(true)
                .list();
    }


    public <T> T getOneByField(Class<T> clazz, String fieldName, Object value) {
        return (T) sessionFactory.getCurrentSession()
                .createCriteria(clazz)
                .add(Restrictions.eq(fieldName, value))
                .setCacheable(true)
                .uniqueResult();
    }

    public <T> List<T> getListInByField(Class<T> clazz, String fieldName, Collection value) {
        return (List<T>) sessionFactory.getCurrentSession()
                .createCriteria(clazz)
                .add(Restrictions.in(fieldName, value))
                .setCacheable(true)
                .list();
    }

    public Serializable save(Object userEntity) {
        return sessionFactory.getCurrentSession().save(userEntity);
    }


    public void saveOrUpdate(Object userEntity) {
         sessionFactory.getCurrentSession().saveOrUpdate(userEntity);
    }

    public void update(Object object) {
        sessionFactory.getCurrentSession().update(object);
    }

    public Criteria createCriteria(Class<?> clazz){
        return sessionFactory.getCurrentSession().createCriteria(clazz);
    }

    public void delete(Object userEntity) {
        sessionFactory.getCurrentSession().delete(userEntity);
    }

    public Object unique(String sql){
        return sessionFactory.getCurrentSession().createSQLQuery(sql).uniqueResult();
    }
    public long count(Criteria criteria){
        return (long) criteria
                .setProjection(Projections.rowCount())
                .setCacheable(true)
                .uniqueResult();
    }




//    public void addFiltersToCriteria(Map<String, Object> filterMap, Criteria criteria, Class<?> clazz){
//        if (filterMap != null) {
//            filterMap.forEach((k, v) -> {
//                if (k != null && !k.isEmpty())
//                    log.debug("got field: " + k + " -> " + v);
//                ClassUtil.getFieldType(clazz, k).ifPresent(type -> {
//                    if (ClassUtil.isNumberType(type) || ClassUtil.isEnumType(type)) {
//                        ClassUtil.newInstance(type, v).ifPresent(fieldValue -> {
//                            log.debug("add restriction eq: " + k + " -> " + v);
//                            criteria.add(Restrictions.eq(k, fieldValue));
//                        });
//                    } else if (type == String.class) {
//                        log.debug("add restriction LIKE: " + k + " -> " + v);
//                        criteria.add(Restrictions.like(k, v.toString(), MatchMode.ANYWHERE));
//                    }
//                });
//            });
//        }
//    }

    public void addFiltersToCriteria(Map<String, Object> filterMap, Criteria criteria, Class<?> clazz){
        if (filterMap != null) {
            filterMap.forEach((k, v) -> {
                if (k != null && !k.isEmpty())
                    log.debug("got field: " + k + " -> " + v);
                boolean isDateRange=false;
                String tmpKey="";
                if (v!=null && v.getClass()== Date.class){
                    if (k.startsWith(STARTKEY) && v!=null){
                        tmpKey=k.replace(STARTKEY,"");
                        criteria.add(Restrictions.gt(tmpKey,v));
                        isDateRange=true;
                    }else if (k.startsWith(ENDKEY) && v!=null){
                        tmpKey=k.replace(ENDKEY,"");
                        criteria.add(Restrictions.lt(tmpKey,v));
                        isDateRange=true;
                    }
                }
                if (!isDateRange){
                    ClassUtil.getFieldType(clazz, k).ifPresent(type -> {
                        if (ClassUtil.isNumberType(type) || ClassUtil.isEnumType(type)) {
                            ClassUtil.newInstance(type, v).ifPresent(fieldValue -> {
                                log.debug("add restriction eq: " + k + " -> " + v);
                                criteria.add(Restrictions.eq(k, fieldValue));
                            });
                        } else if (type == String.class) {
                            log.debug("add restriction LIKE: " + k + " -> " + v);
                            criteria.add(Restrictions.like(k, v.toString(), MatchMode.ANYWHERE));
                        }
                    });
                }
            });
        }
    }

}
